package com.bodystm.algorithm;

public class HrCal {
	/*private final int SAMPLE_RATE = 356;
    private final double MS_PER_SAMPLE = ((double)1000 / (double)SAMPLE_RATE);
    private final int MS10 = ((int)(10 / MS_PER_SAMPLE + 0.5));
    private final int MS80 = ((int)(80 / MS_PER_SAMPLE + 0.5));
    private final int MS95 = ((int)(95 / MS_PER_SAMPLE + 0.5));
    private final int MS100 = ((int)(100 / MS_PER_SAMPLE + 0.5));
    private final int MS150 = ((int)(150 / MS_PER_SAMPLE + 0.5));
    private final int MS195 = ((int)(195 / MS_PER_SAMPLE + 0.5));
    private final int MS220 = ((int)(220 / MS_PER_SAMPLE + 0.5));
    private final int MS360 = ((int)(360 / MS_PER_SAMPLE + 0.5));
    private final int MS1000 = SAMPLE_RATE;
    private final int MS1500 = ((int)(1500 / MS_PER_SAMPLE));
    private final int DERIV_LENGTH = MS10;
    private final int WINDOW_WIDTH = MS80;
    private final int DER_DELAY = WINDOW_WIDTH + MS100 + MS195;
    private final int AF_LEN = MS360;
    private final int PRE_BLANK = MS95;

    int AFIndicator = 0;
    int[] DDBuffer=new int[DER_DELAY]; int DDPtr;  Buffer holding derivative data. 
    int[] AFdata=new int[AF_LEN]; int AFPtr;
    int Peakmin = 0;    // Prevents peaks detections smaller than a given number. *** need modification
    double TH = .3125;
    final int MEMMOVELEN = 7 * Integer.SIZE;
    public HrCal()
    {
    }

    int[] derBuff = new int[DERIV_LENGTH]; int derI = 0;
    int deriv1(int x, int init)
    {
        try
        {
            int y;
            if (init != 0)
            {
                for (derI = 0; derI < DERIV_LENGTH; ++derI)
                    derBuff[derI] = 0;
                derI = 0;
                return (0);
            }

            y = x - derBuff[derI];
            derBuff[derI] = x;
            if (++derI == DERIV_LENGTH)
                derI = 0;
            return (y);
        }
        catch (Exception e)
        {

        }
        
    }
    int[] derBuff2 = new int[DERIV_LENGTH]; int derI2 = 0;
    int deriv2(int x, int init)
    {
        try
        {
            int y;

            if (init != 0)
            {
                for (derI2 = 0; derI2 < DERIV_LENGTH; ++derI2)
                    derBuff2[derI2] = 0;
                derI2 = 0;
                return (0);
            }

            y = x - derBuff2[derI2];
            derBuff2[derI2] = x;
            if (++derI2 == DERIV_LENGTH)
                derI2 = 0;
            return (y);
        }
        catch (Exception e)
        {

        }
    }
    int sum = 0;
    int[] data = new int[WINDOW_WIDTH];
    int ptr = 0;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="datum"></param>
    /// <param name="init">第一次执行传入1，其他情况都传0</param>
    /// <returns></returns>
    int mvwint(int datum, int init)
    {
        try
        {
            int output;
            if (init == 1)
            {
                for (ptr = 0; ptr < WINDOW_WIDTH; ++ptr)
                    data[ptr] = 0;
                sum = 0;
                ptr = 0;
            }
            sum += datum;
            sum -= data[ptr];
            data[ptr] = datum;
            if (++ptr == WINDOW_WIDTH)
                ptr = 0;
            output = sum / WINDOW_WIDTH;
            return (output);
        }
        catch (Exception e)
        {

        }
    }
    int max = 0, lastDatum;
    int Peak(int datum, int init)
    {
        try
        {
            int pk = 0;

            if (init == 1)
                max = 0;

            if ((datum > lastDatum) && (datum > max))
                max = datum;
            else if (datum < (max >> 1))
            {
                pk = max;
                max = 0;
            }

            lastDatum = datum;
            return (pk);
        }
        catch (Exception e)
        {

        }
       
    }

    int AFCheck(ref int[] dBuf, int dbPtr, int AFmax)
    {
        try
        {
            int nosfg, nosfgl;
            int slop = 0, slopl = 0, n = 0;
            nosfg = AFmax;
            nosfgl = nosfg / 4;
            nosfg = nosfg * 1 / 2;
            for (int t = 4; t < MS360 - 4; ++t)
            {
                int n1, n2, n3, n4, n5, n6, n7, n8;

                n = dbPtr;
                n1 = n + 1; n2 = n + 2; n3 = n + 3; n4 = n + 4;
                n5 = n - 1; n6 = n - 2; n7 = n - 3; n8 = n - 4;
                //upper boundary
                if (n + 1 > AF_LEN - 1)
                {
                    n1 = 0; n2 = 1; n3 = 2; n4 = 3;
                }
                else if (n + 2 > AF_LEN - 1)
                {
                    n2 = 0; n3 = 1; n4 = 2;
                }
                else if (n + 3 > AF_LEN - 1)
                {
                    n3 = 0; n4 = 1;
                }
                else if (n + 4 > AF_LEN - 1)
                {
                    n4 = 0;
                }
                //lower boundary
                if (n - 1 < 0)
                {
                    n5 = AF_LEN - 1; n6 = AF_LEN - 2; n7 = AF_LEN - 3; n8 = AF_LEN - 4;
                }
                else if (n - 2 < 0)
                {
                    n6 = AF_LEN - 1; n7 = AF_LEN - 2; n8 = AF_LEN - 3;
                }
                else if (n - 3 < 0)
                {
                    n7 = AF_LEN - 1; n8 = AF_LEN - 2;
                }
                else if (n - 4 < 0)
                {
                    n8 = AF_LEN - 1;
                }

                if (Math.Abs(AFdata[n]) > nosfg)
                {
                    if ((
                        (AFdata[n7] - AFdata[n8]) > 0
                        && (AFdata[n6] - AFdata[n7]) > 0
                        && (AFdata[n5] - AFdata[n6]) > 0
                        && (AFdata[n] - AFdata[n5]) >= 0
                        && (AFdata[n] - AFdata[n1]) > 0
                        && (AFdata[n1] - AFdata[n2]) > 0
                        && (AFdata[n2] - AFdata[n3]) > 0
                        && (AFdata[n3] - AFdata[n4]) > 0
                        )
                        ||
                        (
                        (AFdata[n7] - AFdata[n8]) < 0
                        && (AFdata[n6] - AFdata[n7]) < 0
                        && (AFdata[n5] - AFdata[n6]) < 0
                        && (AFdata[n] - AFdata[n5]) <= 0
                        && (AFdata[n] - AFdata[n1]) < 0
                        && (AFdata[n1] - AFdata[n2]) < 0
                        && (AFdata[n2] - AFdata[n3]) < 0
                        && (AFdata[n3] - AFdata[n4]) < 0
                        )
                        )
                        slop++;
                }

                if (Math.Abs(AFdata[n]) > nosfgl)
                {
                    if ((
                        (AFdata[n7] - AFdata[n8]) > 0
                        && (AFdata[n6] - AFdata[n7]) > 0
                        && (AFdata[n5] - AFdata[n6]) > 0
                        && (AFdata[n] - AFdata[n5]) >= 0
                        && (AFdata[n] - AFdata[n1]) > 0
                        && (AFdata[n1] - AFdata[n2]) > 0
                        && (AFdata[n2] - AFdata[n3]) > 0
                        && (AFdata[n3] - AFdata[n4]) > 0
                        )
                        ||
                        (
                        (AFdata[n7] - AFdata[n8]) < 0
                        && (AFdata[n6] - AFdata[n7]) < 0
                        && (AFdata[n5] - AFdata[n6]) < 0
                        && (AFdata[n] - AFdata[n5]) <= 0
                        && (AFdata[n] - AFdata[n1]) < 0
                        && (AFdata[n1] - AFdata[n2]) < 0
                        && (AFdata[n2] - AFdata[n3]) < 0
                        && (AFdata[n3] - AFdata[n4]) < 0
                        )
                        )
                        slopl++;
                }
                if (++dbPtr == AF_LEN)
                    dbPtr = 0;
            }
            if (slop >= 4)
                return 1;
            else
            {
                if (slopl >= 6)
                    return 1;
                else
                    return 0;
            }
        }
        catch (Exception e)
        {

        }
        
    }

    int BLSCheck(ref int[] dBuf, int dbPtr)
    {
        try
        {
            int max, min, maxt = 0, mint = 0, t, x;
            max = min = 0;

            for (t = 0; t < MS220; ++t)
            {
                x = dBuf[dbPtr];
                if (x > max)
                {
                    maxt = t;
                    max = x;
                }
                else if (x < min)
                {
                    mint = t;
                    min = x;
                }
                if (++dbPtr == DER_DELAY)
                    dbPtr = 0;
            }

            min = -min;

             Possible beat if a maximum and minimum pair are found
            where the interval between them is less than 150 ms. 

            if ((max > (min >> 3)) && (min > (max >> 3)) &&
                (Math.Abs(maxt - mint) < MS220))//***********
                return (0);

            else
                return (1);
        }
        catch (Exception e)
        {

        }
        
    }

    int mean(ref int[] array, int datnum)
    {
        try
        {
            int sum;
            int i;

            for (i = 0, sum = 0; i < datnum; ++i)
                sum += array[i];
            sum /= datnum;
            return (sum);
        }
        catch (Exception e)
        {

        }
        
    }

    int thresh(int qmean, int nmean)
    {
        try
        {
            int thrsh, dmed;
            double temp;
            dmed = qmean - nmean;
            	thrsh = nmean + (dmed>>2) + (dmed>>3) + (dmed>>4); 
            temp = dmed;
            temp *= TH;
            dmed = (int)temp;
            thrsh = nmean + dmed;  dmed * THRESHOLD 
            return (thrsh);

        }
        catch (Exception e)
        {

        }
        
    }

    int maxAF(ref int[] dBuf)
    {
        try
        {
            int x, max = 0;
            for (int t = 0; t < MS360; ++t)
            {
                x = dBuf[t];
                if (x > max)
                    max = x;
            }
            return max;
        }
        catch (Exception e)
        {

        }
        
    }

    int preBlankCnt, tempPeak;
    int det_thresh, qpkcnt = 0;
    int initBlank, initMax;
    int nmean, qmean, rrmean;
    int[] qrsbuf = new int[8];int[] noise = new int[8]; int[] rrbuf=new int[8];
    int count, sbpeak = 0, sbloc, sbcount = MS1500;
    int[] rsetBuff = new int[8]; int rsetCount = 0;
    //datum 中值滤波之后的y值,datum为0
    //init 第一次调用输入1，其他都为0
    public int QRSDet(int datum, int init)
    {
        try
        {
            int fdatum;
            int i, newPeak, aPeak;

            //initiate
            if (init == 1)
            {
                for (i = 0; i < 8; ++i)
                {
                    noise[i] = 0;    Initialize noise buffer 
                    rrbuf[i] = MS1000; and R-to-R interval buffer. 
                }

                qpkcnt = count = sbpeak = 0;
                initBlank = initMax = preBlankCnt = DDPtr = 0;
                sbcount = MS1500;

                mvwint(0, 1);
                deriv1(0, 1);
                deriv2(0, 1);
                Peak(0, 1);
                return 0;
            }

            //calculus
            fdatum = deriv2(datum, 0);  // Take the derivative.
            fdatum = Math.Abs(fdatum);               // Take the absolute value.
            fdatum = mvwint(fdatum, 0);

            // Wait until normal detector is ready before calling early detections. 
            aPeak = Peak(fdatum, 0);
            if (aPeak < Peakmin)
                aPeak = 0;

            // Hold any peak that is detected for 200 ms in case a bigger one comes along.  
            // There can only be one QRS complex in any 200 ms window.
            newPeak = 0;
            if (aPeak != 0 && preBlankCnt == 0)          // If there has been no peak for 200 ms
            {                                       // save this one and start counting.
                tempPeak = aPeak;
                preBlankCnt = PRE_BLANK;            // MS200
            }

            else if (aPeak == 0 && preBlankCnt != 0) // If we have held onto a peak for
            {                                       // 200 ms pass it on for evaluation.
                if (--preBlankCnt == 0)
                    newPeak = tempPeak;
            }

            else if (aPeak != 0)                         // If we were holding a peak, but
            {                                       // this ones bigger, save it and
                if (aPeak > tempPeak)               // start counting to 200 ms again.
                {
                    tempPeak = aPeak;
                    preBlankCnt = PRE_BLANK; // MS200
                }
                else if (--preBlankCnt == 0)
                    newPeak = tempPeak;
            }

            DDBuffer[DDPtr] = deriv1(datum, 0);
            if (++DDPtr == DER_DELAY)
                DDPtr = 0;

            AFdata[AFPtr] = datum;
            if (++AFPtr == AF_LEN)
                AFPtr = 0;

            if (qpkcnt < 8)
            {
                ++count;
                if (newPeak > 0) count = WINDOW_WIDTH;
                if (++initBlank == MS1000)
                {
                    initBlank = 0;
                    qrsbuf[qpkcnt] = initMax;

                    if (Peakmin < initMax / 5)
                        Peakmin = initMax / 5;

                    initMax = 0;
                    ++qpkcnt;

                    if (qpkcnt == 8)
                    {
                        qmean = mean(ref qrsbuf, 8);
                        nmean = 0;
                        rrmean = MS1000;
                        sbcount = MS1500 + MS150;
                        det_thresh = thresh(qmean, nmean);
                    }
                }
                if (newPeak > initMax)
                    initMax = newPeak;
            }
            else     Else test for a qrs. 
            {
                ++count;
                if (newPeak > 0)
                {
                    if (BLSCheck(ref DDBuffer, DDPtr) == 0)
                    {
                        // Classify the beat as a QRS complex if the peak is larger than the detection threshold.
                        if (newPeak > det_thresh)
                        {
                            if (AFCheck(ref AFdata, AFPtr, maxAF(ref AFdata)) != 0)
                            {
                                count = WINDOW_WIDTH;
                                AFIndicator = 1;
                                return 0;
                            }

                            if (AFIndicator != 0)
                            {
                                count = WINDOW_WIDTH;
                                AFIndicator = 0;
                                return 0;
                            }
                            else
                            {
                                //memmove(&qrsbuf[1], qrsbuf, MEMMOVELEN);
                                //Console.WriteLine("hou" + qrsbuf[0] + " " + qrsbuf[1] + " " + qrsbuf[2] + " " + qrsbuf[3] + " " + qrsbuf[4]);
                                memmove(ref qrsbuf);
                               // Console.WriteLine("hou" + qrsbuf[0] + " " + qrsbuf[1] + " " + qrsbuf[2] + " " + qrsbuf[3] + " " + qrsbuf[4]);
                                qrsbuf[0] = newPeak;
                                qmean = mean(ref qrsbuf, 8);
                                det_thresh = thresh(qmean, nmean);
                                //memmove(&rrbuf[1], rrbuf, MEMMOVELEN);
                                memmove(ref rrbuf);
                                rrbuf[0] = count - WINDOW_WIDTH;
                                rrmean = mean(ref rrbuf, 8);
                                sbcount = rrmean + (rrmean >> 1) + WINDOW_WIDTH;
                                count = WINDOW_WIDTH;
                                sbpeak = 0;
                                initBlank = initMax = rsetCount = 0;

                                #region 新加方法后改变返回方式
                                //return 0;
                                //return rrbuf[0];
                                nCount++;

                                if (nCount > 5)
                                {
                                    nCount = 9;
                                    //Console.WriteLine(rrbuf[0] + " " + rrbuf[1] + " " + rrbuf[2] + " " + rrbuf[3] + " " + rrbuf[4]);
                                    return BPmean(ref rrbuf, 5);
                                }
                                else
                                    return 0;// rrbuf[0];

                                #endregion
                            }
                        }

                        // If a peak isn't a QRS update noise buffer and estimate.
                        // Store the peak for possible search back.
                        else
                        {
                            //memmove(&noise[1], noise, MEMMOVELEN);
                            memmove(ref noise);
                            noise[0] = newPeak;
                            nmean = mean(ref noise, 8);
                            det_thresh = thresh(qmean, nmean);

                            // Don't include early peaks (which might be T-waves)
                            // in the search back process.  A T-wave can mask
                            // a small following QRS.

                            if ((newPeak > sbpeak) && ((count - WINDOW_WIDTH) >= MS360))
                            {
                                sbpeak = newPeak;
                                sbloc = count - WINDOW_WIDTH;
                            }
                        }
                    }

                }

                 Test for search back condition.  If a QRS is found in  
                 search back update the QRS buffer and det_thresh.      

                if ((count > sbcount) && (sbpeak > (det_thresh >> 1)))
                {
                    //memmove(&qrsbuf[1], qrsbuf, MEMMOVELEN);
                    memmove(ref qrsbuf);
                    qrsbuf[0] = sbpeak;
                    qmean = mean(ref qrsbuf, 8);
                    det_thresh = thresh(qmean, nmean);
                    //memmove(&rrbuf[1], rrbuf, MEMMOVELEN);
                    memmove(ref rrbuf);
                    rrbuf[0] = sbloc;
                    rrmean = mean(ref rrbuf, 8);
                    sbcount = rrmean + (rrmean >> 1) + WINDOW_WIDTH;
                    count = count - sbloc;
                    sbpeak = 0;

                    initBlank = initMax = rsetCount = 0;

                    #region 新加方法后改变返回方式
                    //return 0;
                    //return rrbuf[0];
                    nCount++;

                    if (nCount >5)
                    {
                        nCount = 9;
                        //Console.WriteLine(rrbuf[0]+" "+rrbuf[1] + " " + rrbuf[2] + " " + rrbuf[3] + " " + rrbuf[4]);
                        return BPmean(ref rrbuf, 5);
                    }
                    else
                        return 0;// rrbuf[0];

                    #endregion
                }
            }

            if (qpkcnt == 8)
            {
                if (++initBlank == MS1000)
                {
                    initBlank = 0;
                    rsetBuff[rsetCount] = initMax;
                    initMax = 0;
                    ++rsetCount;

                    // Reset threshold if it has been 8 seconds without
                    // a detection.

                    if (rsetCount == 8)
                    {
                        for (i = 0; i < 8; ++i)
                        {
                            qrsbuf[i] = rsetBuff[i];
                            noise[i] = 0;
                        }
                        qmean = mean(ref rsetBuff, 8);
                        nmean = 0;
                        rrmean = MS1000;
                        sbcount = MS1500 + MS150;
                        det_thresh = thresh(qmean, nmean);
                        initBlank = initMax = rsetCount = 0;
                    }
                }
                if (newPeak > initMax)
                    initMax = newPeak;
            }

            return 0;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return 0;
        }

        

    }

    private void memmove(ref int[] arr)
    {
        try
        {
            int num = arr.Length - 1;
            while (num > 0)
            {
                arr[num] = arr[num - 1];
                num--;
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            return;
        }
       
    }

    public int nCount = 0;
    int BPmean(ref int[] array, int datnum)
    {
        try
        {
            int x, max = 0, min = 10000;
            int maxt = 0, mint = 0;
            int[] p = new int[8];

            for (int t = 0; t < datnum; ++t)
            {
                p[t] = array[t];
            }
            // locate the maximum and minimum
            for (int t = 0; t < datnum; ++t)
            {
                x = p[t];
                if (x > max)
                {
                    max = x;
                    maxt = t;
                }
                if (x < min)
                {
                    min = x;
                    mint = t;
                }
            }
            //delete the compoent of max and min
            int sum = 0;
            for (int i = 0; i < datnum; ++i)
            {
                if (i != maxt && i != mint)
                    sum += p[i];
            }
            if (maxt != mint)
                return sum / (datnum - 2);
            else
                return sum / (datnum - 1);
        }
        catch (Exception e)
        {

        }
        
    }*/
}
